#include <bits/stdc++.h>

using namespace std;

using ll = long long;

#ifdef LLT_DBG
#define FR freopen("in.txt", "r", stdin)
#else
#define FR
#endif

vector<vector<int>> adj;
vector<vector<int>> sadj;

int low[200005];
int dfn[200005];
bool bv[200005];
int tot;
int n, m;
int nn;

ll wi[400005];

stack<pair<int, int>> sta;

void tarjan(int u, int r)
{
    dfn[u] = low[u] = ++tot;
    bool fg = false;
    int sub = 0;
    for (int to : adj[u])
    {
        if (!dfn[to])
        {
            sub++;
            sta.push({u, to});
            tarjan(to, r);
            low[u] = min(low[u], low[to]);
            if (low[to] >= dfn[u])
            { // v-scc
                fg = true;
                pair<int, int> e;
                nn++;
                do
                {
                    e = sta.top();
                    sta.pop();
                    sadj[nn].push_back(e.first);
                    sadj[nn].push_back(e.second);

                    sadj[e.first].push_back(nn);
                    sadj[e.second].push_back(nn);
                } while (e != make_pair(u, to));
            }
        }
        else
        {
            low[u] = min(low[u], dfn[to]);
        }
    }

    if ((u == r && sub >= 2) || (u != r && fg))
    {
        bv[u] = true;
    }
}

// 从子节点圆点到根节点路径和
ll dp[400005];
// 子树中圆点的数量
ll scnt[400005];

ll ans;

bool vis[400005];

void dfs(int u, int r)
{
    vis[u] = true;
    if (u <= n)
    {
        dp[u] += wi[u];
        scnt[u] = 1;
    }

    for (int to : sadj[u])
    {
        if (to == r)
            continue;
        dfs(to, u);
        ans += (dp[u] * scnt[to]) + (dp[to] * scnt[u]);
        scnt[u] += scnt[to];
        dp[u] += dp[to] + scnt[to] * wi[u];
    }
}

void solve()
{
    cin >> n >> m;
    nn = n;
    adj.resize(n + 1);
    sadj.resize(2 * n + 1);

    for (int i = 1; i <= m; i++)
    {
        int u, v;
        cin >> u >> v;
        adj[u].push_back(v);
        adj[v].push_back(u);
    }

    for (int i = 1; i <= n; i++)
    {
        if (!dfn[i])
            tarjan(i, i);
    }

    // 去重
    for (int i = 1; i <= nn; i++)
    {
        vector<int> &item = sadj[i];
        sort(item.begin(), item.end());
        item.erase(unique(item.begin(), item.end()), item.end());
    }

    // 统计点权

    for (int i = 1; i <= n; i++)
    {
        wi[i] = -1;
    }
    for (int i = n + 1; i <= nn; i++)
    {
        wi[i] = sadj[i].size();
    }

    // 树形DP
    for (int i = 1; i <= nn; i++)
    {
        if (!vis[i])
            dfs(i, i);
    }

    cout << ans * 2 << endl;
}

int main()
{
    FR;
    solve();
    return 0;
}